#include <iostream> 
#include <sstream> 
#include <vector> 
#include <string> 
#include <stdio.h> 
#include <stdlib.h> 
#include <stdarg.h> 

template<typename R, bool integral>
struct string_converter {
    R(*f_)(const char*, char **, int);
    
    string_converter(R(*func)(const char*, char **, int)) {
        f_ = func;
    }

    R operator()(const char* str, char ** endptr) {
        return f_(str, endptr, 10);
    }
};

template<typename R>
struct string_converter<R, false> {
    R(*f_)(const char*, char **);

    string_converter(R(*func)(const char*, char **)) {
        f_ = func;
    }

    R operator()(const char* str, char ** endptr) {
        return f_(str, endptr);
    }
};

template<typename T, typename R, bool integral>
static int convert(const char* str, T& value, string_converter<R, integral>& func) {
    char * endptr = nullptr;
    
    value = func(str, &endptr);
    errno = 0;
    if (errno || *endptr == '\0' || endptr == str)
        return -EINVAL;

    return 0;
}

template<typename T>
struct string_traits {
    static std::string to_string(const T& value) {
        return value.tostring();
    }

    static int from_string(const char* str, T& value) {
        return value.from_string(str);
    }
};

#define define_trivial_string_traits(T, R, integral, conv_func) \
    template<> \
    struct string_traits<T> { \
        static std::string to_string(const T& value) { \
            return std::to_string(value);  \
        } \
        static int from_string(const char* str, T& value) { \
            string_converter<R, integral> cv(conv_func); \
            return convert(str, value, cv); \
        } \
    }

define_trivial_string_traits(uint64_t, unsigned long long, true, strtoull);
define_trivial_string_traits(int64_t, long long, true, strtoll);
define_trivial_string_traits(uint32_t, unsigned long, true, strtoul);
define_trivial_string_traits(int32_t, long, true, strtol);
define_trivial_string_traits(float, float, false, strtof);
define_trivial_string_traits(double, double, false, strtod);

#undef define_trivial_string_traits

int split_string(const char* str, char delim, std::vector<std::string>& vec) {
    if (str == nullptr) return -EINVAL;
    std::stringstream ss;
    ss.str(str);

    std::string item;
    while(std::getline(ss, item, delim))
        vec.push_back(item);

    return 0;
}

void replace_string(std::string& str, const std::string src, const std::string dst) {
    if (str.empty()) return;

    size_t found = 0;
    while((found = str.find(src)) != std::string::npos) {
        str.replace(found, src.size(), dst.c_str());
        found += src.size();
    }
}

int fill_string(std::string& str, const char* format, ...) {
    static char buff[8192] = "\0";

    va_list args;
    va_start(args, format);
    int ret = vsnprintf(buff, sizeof(buff), format, args);
    va_end(args);

    buff[sizeof(buff) - 1] = '\0';
    str = buff;

    return ret;
}

int main(int argc, char **argv) {
    std::vector<std::string> ss;
    split_string("abc#", '#', ss);
    printf("%lu %s\n", ss.size(), ss[0].c_str());
    uint64_t value = 12312342;
    printf("%s\n", string_traits<uint64_t>::to_string(value).c_str());
    string_traits<uint64_t>::from_string("1233434", value);
    printf("%lu\n", value);

    std::string str1("There are two needles in this haystack with needles.");
    std::string str2("needle");

    size_t size = str1.find(str2);
    size = str1.find("needles are small", size + str2.size(), 6);
    if (size != std::string::npos)
        printf("find:%lu\n", size);

    std::string aa("123xx123xx123xx123xxxx!!");
    printf("src:%s\n", aa.c_str());
    replace_string(aa, "xx", "hello");
    printf("now:%s\n", aa.c_str());

    fill_string(aa, "%d%s", 2, "xxhelo");
    printf("xx:%s\n", aa.c_str());

    localtime()

    return 0;
}
